﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using NSMyUtils;
using System.Threading;
using EngineeringGraf;

/* * Version 1.34.
    Allowed for CTun version 2.7 having one less parameter
 *  Fixed reset of the Lat/Lon average when loading a new file, to prevent bad GPS lines
 *  
 * Version 1.33.
 * Fixed bug for european expecting comma's in double strings instead of periods.
 * Fixed the Yaw Picture to get info from Yaw instead of Mag Sensor
 * 
 
 * *  * Version 1.32.
 *  Took Dereks suggestion, playback starts where you drop the slider
 
 * *  Now this is a really cool feature I thought of while using it, and wishing it were a feature:
 *     As you slide the slider in the graph, the main window updates using that location,
 *      Now that is COOOL!
 *      
 *  * Version 1.31.
 *  added a map Legend
 *  Added red/green for things on/off the graph
 *  Fixed Unknown mode returning Circle, also RTL returned circle.
 *  Fixed vertical scale of removed point left on screen.
 *  Fixed graph not working right after deleting a point

 * Version 1.3. 
 * Mainly worked on Engineering Graphs, then added the CTUN and NTUN parameters.
 * 
 * Version1.2
 * Added Engineering Graphs
 
 * * Version 1.1, 
 * made it work on bad lines in file, with a message.
 * Added CIRCLE and ALT_HOLD to modes.
 * added a different path color for modes other than auto/stabilize/Loiter
 * */
namespace APMLogVisualizer
{
    public partial class Form1 : Form
    {
        private System.Drawing.Graphics LocGraph = null;
        private System.Drawing.Graphics LayoutGraph = null;
        private LogPointInfo[] lpi = null;
        const int MAXLOGLINES = 65535;
        private String[] LogLines = new String[MAXLOGLINES];
        internal Form1()
        {
            InitializeComponent();
            String[] cla = Environment.GetCommandLineArgs();
            this.Text = "APMLogVisualizer Version " + MyVersion + " by Dan Gray";
            for (int i = 0; i < MAXLOGLINES; i++) LogLines[i] = "";
            try
            {
                LayoutGraph = this.PBCopters.CreateGraphics();
                LocGraph = this.PBLocation.CreateGraphics();
            }
            catch 
            {
                LocGraph = null;
                MessageBox.Show("Couldn't make graphics!!!", "Sorry!");
            }
            for (int i = 0; i < MAXLOGLINES; i++) LogLines[i] = "";
            if (cla.Length > 1)
            {
                LBPathFile.Text = cla[1];
                StartUpDoLog = true;
            }
            if (DatGraf == null)
            {
                DatGraf = new DataGraph();
                DatGraf.Show();
                DatGraf.Visible = false;
            }

        }
        String MyVersion = "1.34";
        bool InLoadFile = false;
        int InLoadFileCnt = 0;
        private void BTLoadFile_Click(object sender, EventArgs e)
        {
            ClearGraph();
            InLoadFile = true;
            InLoadFileCnt = 0;
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "Load an APM Log File:";
            ofd.Filter = "Load Log Files (*.log)|*.log";
            ofd.RestoreDirectory = true;
            for (int i = 0; i < MAXLOGLINES; i++) LogLines[i] = "";
            if (ofd.ShowDialog(this) == DialogResult.OK)
            {
                LBPathFile.Text = ofd.FileName;
                DoTheLogFile();
            }
            InLoadFile = false;
        }
        bool StartUpDoLog = false;
        int NoOfLogEntries = 0;
        private void DoTheLogFile()
        {
            ClearPictureBox();
            BadLinesInLogFile = 0;
            BadLines = "";
            FirstReading = false;
            String istg = "";
            String FN = "";
            for (int i = 0; i < MAXLOGLINES; i++) LogLines[i] = "";
            if (File.Exists(LBPathFile.Text))
            {
                FN = LBPathFile.Text;
            }
            else
            {
                OpenFileDialog ofd = new OpenFileDialog();
                ofd.Title = "Load an APM Log File:";
                ofd.Filter = "Load Log Files (*.log)|*.log";
                ofd.RestoreDirectory = true;
                if (ofd.ShowDialog(this) == DialogResult.OK)
                {
                    FN = ofd.FileName;
                }
            }
            {
                LBPathFile.Text = FN;
                try
                {
                    StreamReader sr = File.OpenText(FN);
                    int ptr = 0;
                    while ((istg = sr.ReadLine()) != null)
                    {
                        if (ptr < MAXLOGLINES && istg.Length > 0)
                        {
                            LogLines[ptr++] = istg;
                        }
                    }
                    sr.Close();
                    NoOfLogEntries = ptr;
                    lpi = new LogPointInfo[NoOfLogEntries];
                    for (int j = 0; j < NoOfLogEntries; j++)
                    {
                        lpi[j] = new LogPointInfo();
                        lpi[j].Mode = 0;
                    }
                    TrBCurStep.Maximum = ptr;
                    TrBCurStep.Value = 0;
                    for (; ptr < MAXLOGLINES; ptr++) LogLines[ptr] = "";
                    bool GPSFound = false;
                    bool ATTFound = false;
                    bool CurrFound = false;
                    bool MOTFound = false;
                    bool MODFound = false;
                    
                    for (int k = 0; k < NoOfLogEntries; k++)
                    {
                        if (k > 0 && lpi[k-1].Mode != MyUtils.AUTO)
                        {
                            lpi[k].CMDAlt = 0;
                            lpi[k].CMDCurrentNum = 0;
                            lpi[k].CMDID = 0;
                            lpi[k].CMDLat = 0;
                            lpi[k].CMDLon = 0;
                            lpi[k].CMDOptions = 0;
                            lpi[k].CMDP1 = 0;
                            lpi[k].CMDTotal = 0;
                        }
                        if (LogLines[k].IndexOf("GPS,") >= 0)
                        {
                            GetGPSLineData(LogLines[k], ref lpi[k], k);
                            if (!GPSFound)
                            {
                                GPSFound = true;
                                for (int l = 0; l < k; l++)
                                {
                                    CopyGPSLogPointInfo(lpi[l], lpi[k]);
                                }
                            }
                        }
                        else if (LogLines[k].IndexOf("ATT,") >= 0)
                        {
                            GetATTLineData(LogLines[k], ref lpi[k]);
                            if (!ATTFound)
                            {
                                ATTFound = true;
                                for (int l = 0; l < k; l++)
                                {
                                    CopyATTLogPointInfo(lpi[l], lpi[k]);
                                }
                            }
                        }
                        else if (LogLines[k].IndexOf("CURR,") >= 0)
                        {
                            GetCurrLineData(LogLines[k], ref lpi[k]);
                            if (!CurrFound)
                            {
                                CurrFound = true;
                                for (int l = 0; l < k; l++)
                                {
                                    CopyCurrLogPointInfo(lpi[l], lpi[k]);
                                }
                            }
                        }

                        else if (LogLines[k].IndexOf("MOT,") >= 0)
                        {
                            GetMotLineData(LogLines[k], ref lpi[k]);
                            if (!MOTFound)
                            {
                                MOTFound = true;
                                for (int l = 0; l < k; l++)
                                {
                                    CopyMotLogPointInfo(lpi[l], lpi[k]);
                                }
                            }
                        }
                        else if (LogLines[k].IndexOf("CMD,") >= 0)
                        {
                            GetCMDLineData(LogLines[k], ref lpi[k]);
                        }
                        else if (LogLines[k].IndexOf("NTUN,") >= 0)
                        {
                            GetNTunLineData(LogLines[k], ref lpi[k]);
                        }
                        else if (LogLines[k].IndexOf("CTUN,") >= 0)
                        {
                            GetCTunLineData(LogLines[k], ref lpi[k]);
                        }
                        else if (LogLines[k].IndexOf("PM,") >= 0)
                        {
                            GetPMLineData(LogLines[k], ref lpi[k]);
                        }
                        else if (LogLines[k].IndexOf("MOD:") >= 0)
                        {
                            lpi[k].Mode = MyUtils.GetMode(LogLines[k]);
                            if (!MODFound)
                            {
                                MODFound = true;
                                for (int l = 0; l < k; l++)
                                {
                                    lpi[l].Mode = lpi[k].Mode;
                                }
                            }
                        }
                        if(k < NoOfLogEntries-1) CopyStickyLogPointInfo(lpi[k + 1], lpi[k]);
                    }
                    //if(!InLocPaint) 
                    DisplayFlightPath();
                    //DisplayCommands();
                    DoStep(1);
                }
                catch
                {
                    MessageBox.Show("Load Log File Failed");
                }
            }
            if (BadLinesInLogFile > 0)
            {
                BigMessages bm = new BigMessages();
                bm.TBMessage.Text = "Your Log File has about " + BadLinesInLogFile.ToString() + " Bad Line(s) in it.\r\n" + BadLines;
                bm.Text = "Rejected lines in log file....";
                bm.ShowDialog();


//                MessageBox.Show("Your Log File has about " + BadLinesInLogFile.ToString() + " Bad Line(s) in it.\r\n" + BadLines, "Rejected lines in log file....");
            }
        }
        private void CopyLogPointInfo(LogPointInfo lpDest, LogPointInfo lpSource)
        {
            lpDest.mSecs = lpSource.mSecs;
            lpDest.Sats = lpSource.Sats;
            lpDest.Lat = lpSource.Lat;
            lpDest.Lon = lpSource.Lon;
            lpDest.MixAlt = lpSource.MixAlt;
            lpDest.GPSAlt = lpSource.GPSAlt;
            lpDest.GRSpeed = lpSource.GRSpeed;
            lpDest.CRS = lpSource.CRS;
            lpDest.MagHeading = lpSource.MagHeading;
            lpDest.Mode = lpSource.Mode;
            lpDest.Mot1 = lpSource.Mot1;
            lpDest.Mot2 = lpSource.Mot2;
            lpDest.Mot3 = lpSource.Mot3;
            lpDest.Mot4 = lpSource.Mot4;
            lpDest.Pitch = lpSource.Pitch;
            lpDest.PitchIN = lpSource.PitchIN;
            lpDest.Roll = lpSource.Roll;
            lpDest.RollIN = lpSource.RollIN;
            lpDest.Yaw = lpSource.Yaw;
            lpDest.YawIN = lpSource.YawIN;
        }
        private void CopyGPSLogPointInfo(LogPointInfo lpDest, LogPointInfo lpSource)
        {
            lpDest.mSecs = lpSource.mSecs;
            lpDest.Sats = lpSource.Sats;
            lpDest.Lat = lpSource.Lat;
            lpDest.Lon = lpSource.Lon;
            lpDest.MixAlt = lpSource.MixAlt;
            lpDest.GPSAlt = lpSource.GPSAlt;
            lpDest.GRSpeed = lpSource.GRSpeed;
            lpDest.CRS = lpSource.CRS;
        }
        private void CopyATTLogPointInfo(LogPointInfo lpDest, LogPointInfo lpSource)
        {
            lpDest.RollIN = lpSource.RollIN;
            lpDest.Roll = lpSource.Roll;
            lpDest.MagHeading = lpSource.MagHeading;
            lpDest.Pitch = lpSource.Pitch;
            lpDest.PitchIN = lpSource.PitchIN;
            lpDest.Yaw = lpSource.Yaw;
            lpDest.YawIN = lpSource.YawIN;
        }
        private void CopyCurrLogPointInfo(LogPointInfo lpDest, LogPointInfo lpSource)
        {
            lpDest.CurrCurrent = lpSource.CurrCurrent;
            lpDest.CurrCurrentTotal = lpSource.CurrCurrentTotal;
            lpDest.CurrThrottleIn = lpSource.CurrThrottleIn;
            lpDest.CurrThrottleTotal = lpSource.CurrThrottleTotal;
            lpDest.CurrVoltage = lpSource.CurrVoltage;
        }
        private void CopyMotLogPointInfo(LogPointInfo lpDest, LogPointInfo lpSource)
        {
            lpDest.Mot1 = lpSource.Mot1;
            lpDest.Mot2 = lpSource.Mot2;
            lpDest.Mot3 = lpSource.Mot3;
            lpDest.Mot4 = lpSource.Mot4;
        }
        private void CopyStickyLogPointInfo(LogPointInfo lpDest, LogPointInfo lpSource)
        {
            lpDest.Mode = lpSource.Mode;
            lpDest.mSecs = lpSource.mSecs;
            lpDest.Sats = lpSource.Sats;
            lpDest.Lat = lpSource.Lat;
            lpDest.Lon = lpSource.Lon;
            lpDest.MixAlt = lpSource.MixAlt;
            lpDest.GPSAlt = lpSource.GPSAlt;
            lpDest.GRSpeed = lpSource.GRSpeed;
            lpDest.CRS = lpSource.CRS;
            
            lpDest.RollIN = lpSource.RollIN;
            lpDest.Roll = lpSource.Roll;
            lpDest.MagHeading = lpSource.MagHeading;
            lpDest.Pitch = lpSource.Pitch;
            lpDest.PitchIN = lpSource.PitchIN;
            lpDest.Yaw = lpSource.Yaw;
            lpDest.YawIN = lpSource.YawIN;

            lpDest.Mot1 = lpSource.Mot1;
            lpDest.Mot2 = lpSource.Mot2;
            lpDest.Mot3 = lpSource.Mot3;
            lpDest.Mot4 = lpSource.Mot4;
            lpDest.CMDAlt = lpSource.CMDAlt;
            lpDest.CMDCurrentNum = lpSource.CMDCurrentNum;
            lpDest.CMDID = lpSource.CMDID;
            lpDest.CMDLat = lpSource.CMDLat;
            lpDest.CMDLon = lpSource.CMDLon;
            lpDest.CMDOptions = lpSource.CMDOptions;
            lpDest.CMDP1 = lpSource.CMDP1;
            lpDest.CMDTotal = lpSource.CMDTotal;

            lpDest.CTunThrotIn = lpSource.CTunThrotIn;
            lpDest.CTunSonarAlt = lpSource.CTunSonarAlt;
            lpDest.CTunBaroAlt = lpSource.CTunBaroAlt;
            lpDest.CTunWPAlt = lpSource.CTunWPAlt;
            lpDest.CTunNavThrottle = lpSource.CTunNavThrottle;
            lpDest.CTunAngleBoost = lpSource.CTunAngleBoost;
            lpDest.CTunManualBoost = lpSource.CTunManualBoost;
            lpDest.CTunClimbRate = lpSource.CTunClimbRate;
            lpDest.CTunRC3ServoOut = lpSource.CTunRC3ServoOut;
            lpDest.CTunAltHoldInt = lpSource.CTunAltHoldInt;
            lpDest.CTunThrottleInt = lpSource.CTunThrottleInt;

            lpDest.NTunWPDist = lpSource.NTunWPDist;
            lpDest.NTunTargetBearing = lpSource.NTunTargetBearing;
            lpDest.NTunLonErr = lpSource.NTunLonErr;
            lpDest.NTunLatErr = lpSource.NTunLatErr;
            lpDest.NTunNavLon = lpSource.NTunNavLon;
            lpDest.NTunNavLat = lpSource.NTunNavLat;
            lpDest.NTunXSpeed = lpSource.NTunXSpeed;
            lpDest.NTunYSpeed = lpSource.NTunYSpeed;
            lpDest.NTunNavLatI = lpSource.NTunNavLatI;
            lpDest.NTunNavLonI = lpSource.NTunNavLonI;
            
            lpDest.CurrCurrent = lpSource.CurrCurrent;
            lpDest.CurrCurrentTotal = lpSource.CurrCurrentTotal;
            lpDest.CurrThrottleIn = lpSource.CurrThrottleIn;
            lpDest.CurrThrottleTotal = lpSource.CurrThrottleTotal;
            lpDest.CurrVoltage = lpSource.CurrVoltage;

            lpDest.GyroSaturation = lpSource.GyroSaturation;
            lpDest.ADCConstraints = lpSource.ADCConstraints;
            lpDest.DCMRenorms = lpSource.DCMRenorms;
            lpDest.DCMBlowUps = lpSource.DCMBlowUps;
            lpDest.GPSFixCount = lpSource.GPSFixCount;
        }
        private void UpdateGPSMaximums()
        {
            if (lpi == null) return;
            if (LengthX == 0.0)
            {//if here, we have to initialize the four variables center and length, x and y.
                Southest = Northest = lpi[0].Lat;
                Eastest = Westest = lpi[0].Lon;
                Lowest = Highest = lpi[0].GPSAlt;
                for (int i = 0; i < NoOfLogEntries; i++)
                {
                    if (Southest > lpi[i].Lat) Southest = lpi[i].Lat;
                    if (Northest < lpi[i].Lat) Northest = lpi[i].Lat;
                    if (Eastest < lpi[i].Lon) Eastest = lpi[i].Lon;
                    if (Westest > lpi[i].Lon) Westest = lpi[i].Lon;
                    if (Highest < lpi[i].GPSAlt) Highest = lpi[i].GPSAlt;
                    if (Lowest > lpi[i].GPSAlt) Lowest = lpi[i].GPSAlt;
                }
                LengthX = Math.Abs(Eastest - Westest);
                LengthY = Math.Abs(Northest - Southest);

                ScaleX = (PBLocation.Size.Width - 14) / LengthX;
                ScaleY = (PBLocation.Size.Height - 2) / LengthY;
                if (ScaleX > ScaleY) ScaleX = ScaleY; else ScaleY = ScaleX;//deg's per pixel is always the same in x and y.
                ScaleEl = (PBLocation.Size.Height - 2) / (Highest - Lowest);
            }
        }
        private void DrawScales()
        {
                float FrmBot = PBLocation.Size.Height - 15;
                LocGraph.DrawLine(PenScales, 1, FrmBot, PBLocation.Size.Width - 14, FrmBot);
                LocGraph.DrawLine(PenScales, 1, FrmBot, 15, FrmBot - 10);
                LocGraph.DrawLine(PenScales, 1, FrmBot, 15, FrmBot + 10);
                LocGraph.DrawLine(PenScales, PBLocation.Size.Width - 14, FrmBot, PBLocation.Size.Width - 14 - 15, FrmBot - 10);
                LocGraph.DrawLine(PenScales, PBLocation.Size.Width - 14, FrmBot, PBLocation.Size.Width - 14 - 15, FrmBot + 10);
                SolidBrush b = new SolidBrush(Color.Brown);
                PointF p = new PointF(PBLocation.Size.Width/2-60f, PBLocation.Size.Height-15);
                double d1 = Math.Cos(Southest * MyUtils.D2R);
                double d2 = Eastest - Westest;
                double MetersWidth = ((d1 * d2) * MyUtils.Deg2Klicks) * 1000.0;
                String s = (Math.Round(MetersWidth,1)).ToString() + " Meters";
                Font f = new Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                LocGraph.DrawString(s, f, b, p);

                double MetersFS = Math.Round(Highest - Lowest, 1);
                s = "Vertical Height=" + MetersFS.ToString() + " Meters";
                SizeF sf = (LocGraph.MeasureString(s, f));
                PointF px = new PointF(PBLocation.Size.Width - sf.Width, 1);
                LocGraph.DrawString(s, f, b, px);
        }

        private double ScaleX, ScaleY, ScaleEl;
        private void DisplayFlightPath()
        {
            if (LocGraph == null) return;
            UpdateGPSMaximums();
            for (int i = 0; i < NoOfLogEntries; i++)
            {
                {
                    DrawNextLine(lpi[i]);
                }
            }
            DrawScales();
            DrawLegend();
            DisplayCommands();
        }
        void DrawLegend()
        {
            float x = 10;
            float LL = 24;
            float y = PBLocation.Height - 40;
            PointF p = new PointF(PBLocation.Size.Width / 2 - 60f, PBLocation.Size.Height - 15);
            Font f = new Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

            SolidBrush b = new SolidBrush(PenPathStabilize.Color);
            String s = "Stabilize";
            SizeF sf = (LocGraph.MeasureString(s, f));
            PointF px = new PointF(x, y - (sf.Height * 1.25f * 3));
            LocGraph.DrawString(s, f, b, px);
            LocGraph.DrawLine(PenPathStabilize, x + sf.Width + 4, (y + (sf.Height / 2) - sf.Height * 1.25f * 3), x + sf.Width + 4 + LL, (y + (sf.Height / 2) - sf.Height * 1.25f * 3));

            s = "Loiter";
            b = new SolidBrush(PenPathLoiter.Color);
            sf = (LocGraph.MeasureString(s, f));
            px = new PointF(x, y - (sf.Height * 1.25f * 2));
            LocGraph.DrawString(s, f, b, px);
            LocGraph.DrawLine(PenPathLoiter, x + sf.Width + 4, (y + (sf.Height / 2) - sf.Height * 1.25f * 2), x + sf.Width + 4 + LL, (y + (sf.Height / 2) - sf.Height * 1.25f * 2));

            b = new SolidBrush(PenPathAuto.Color);
            s = "Auto";
            sf = (LocGraph.MeasureString(s, f));
            px = new PointF(x, y - (sf.Height * 1.25f * 1));
            LocGraph.DrawString(s, f, b, px);
            LocGraph.DrawLine(PenPathAuto, x + sf.Width + 4, (y + (sf.Height / 2) - sf.Height * 1.25f * 1), x + sf.Width + 4 + LL, (y + (sf.Height / 2) - sf.Height * 1.25f * 1));

            s = "Other Modes";
            b = new SolidBrush(PenPathOther.Color);
            sf = (LocGraph.MeasureString(s, f));
            px = new PointF(x, y - (sf.Height * 1.25f * 0));
            LocGraph.DrawString(s, f, b, px);
            LocGraph.DrawLine(PenPathOther, x + sf.Width + 4, (y + (sf.Height / 2) - sf.Height * 1.25f * 0), x + sf.Width + 4 + LL, (y + (sf.Height / 2) - sf.Height * 1.25f * 0));

        }
        private void DisplayCommands()
        {
            if (LocGraph == null) return;
            UpdateGPSMaximums();
            for (int i = 0; i < NoOfLogEntries; i++)
            {
                {
                    if (lpi[i].CMDID == WayPoint)
                    {
                        DrawWayPoint(lpi[i].CMDLat, lpi[i].CMDLon, lpi[i].CMDAlt);
                    }
                }
            }
        }
        const int WayPoint = 16;
        const int RTL = 20;
        const int Loiter_Unlim = 17;
        const int Loiter_Turns = 18;
        const int Loiter_Time = 19;
        const int Return_To_Launch = 20;
        const int Land = 21;
        const int TakeOff = 22;
        const int ROI = 80;
        const int PathPlanning = 81;
        const int Condition_Delay = 112;
        const int Condition_Change = 113;
        const int Condition_Distance = 114;
        const int Condition_Yaw = 115;
        const int Do_Set_Mode = 176;
        const int Do_Jump = 177;
        const int Do_Change_Speed = 178;
        const int Do_Set_Home = 179;
        const int Do_Set_Parameter = 180;
        const int Do_Set_Relay = 181;
        const int Do_Repeat_Relay = 182;
        const int Do_Set_Servo = 183;
        const int Do_Repeat_Servo = 184;
        const int Do_Digicam_Config = 202;
        const int Do_Digicam_Contr = 203;
        const int Do_Mount_Config = 204;
        const int Do_Mount_Control = 205;
        String IntToCommand(int Cmd)
        {
            if (Cmd == WayPoint) return "WayPoint";
            if (Cmd == RTL) return "RTL";
            if (Cmd == Loiter_Unlim) return "Loiter_UnLim";
            if (Cmd == Loiter_Turns) return "Loiter_Turns";
            if (Cmd == Loiter_Time) return "Loiter_Time";
            if (Cmd == Return_To_Launch) return "Ret_To_Launch";
            if (Cmd == Land) return "Land";
            if (Cmd == TakeOff) return "TakeOff";
            if (Cmd == ROI) return "ROI";
            if (Cmd == PathPlanning) return "PathPlanning";
            if (Cmd == Condition_Delay) return "Conditional_Delay";
            if (Cmd == Condition_Distance) return "Conditional_Distance";
            if (Cmd == Condition_Yaw) return "Conditional_Yaw";
            if (Cmd == Do_Set_Mode) return "Do_Set_Mode";
            if (Cmd == Do_Jump) return "Do_Jump";
            if (Cmd == Do_Change_Speed) return "Do_Change_Speed";
            if (Cmd == Do_Set_Home) return "Do_Set_Home";
            if (Cmd == Do_Set_Parameter) return "Do_Set_Parameter";
            if (Cmd == Do_Set_Relay) return "Do_Set_Relay";
            if (Cmd == Do_Repeat_Relay) return "Do_Repeat_Relay";
            if (Cmd == Do_Set_Servo) return "Do_Set_Servo";
            if (Cmd == Do_Repeat_Servo) return "Do_Repeat_Servo";
            if (Cmd == Do_Digicam_Config) return "Do_Digicam_Config";
            if (Cmd == Do_Digicam_Contr) return "Do_Digicam_Contr";
            if (Cmd == Do_Mount_Config) return "Do_Mount_Config";
            if (Cmd == Do_Mount_Control) return "Do_Mount_Control";
            return "????? " + Cmd.ToString() ;
        }
        double LengthX = 0.0;
        double LengthY = 0.0;
        double Northest = 0.0;
        double Southest = 0.0;
        double Westest = 0.0;
        double Eastest = 0.0;
        double Lowest = 0.0;
        double Highest = 0.0;

        private void ClearPictureBox()
        {
            LengthX = 0.0;
            LengthY = 0.0;
            Northest = 0.0;
            Southest = 0.0;
            Westest = 0.0;
            Eastest = 0.0;
            Lowest = Highest = 0.0;
            LastX = LastY = 0.0;
            LastVY = LastVX = 0;
            LocGraph.Clear(PBLocation.BackColor);
        }
        Pen PenScales = new Pen(Color.Brown, 2);
        Pen PenPathStabilize = new Pen(Color.Red, 2);
        Pen PenPathLoiter = new Pen(Color.DarkMagenta, 2);
        Pen PenPathAuto = new Pen(Color.DarkGreen, 2);
        Pen PenPathOther = new Pen(Color.Chocolate, 2);
        Pen PenWayPoints = new Pen(Color.Black, 5);
        Pen PenVehicleHeight = new Pen(Color.Brown, 6);
        double LastX = 0, LastY = 0;
        private void DrawWayPoint(double Lat, double Lon, double GPSAlt)
        {
            double x, y;
            x = (Lon - Westest) * ScaleX + 1;
            y = (Northest - Lat) * ScaleY + 1;
            float wpl = 9;
            LocGraph.DrawEllipse(PenWayPoints, (float) x-wpl/2, (float) y-wpl/2, wpl, wpl);
        }
        private void DrawNextLine(LogPointInfo lpi)
        {
            double x, y;
            x = (lpi.Lon - Westest) * ScaleX + 1;
            y = (Northest - lpi.Lat) * ScaleY + 1;
            if(LastX == 0 || LastY == 0) 
            {
                LastX = x; LastY = y; return;
            }
            Pen p;
            if (lpi.Mode == MyUtils.STABILIZE) p = PenPathStabilize;
            else if (lpi.Mode == MyUtils.LOITER) p = PenPathLoiter;
            else if (lpi.Mode == MyUtils.AUTO) p = PenPathAuto;
            else p = PenPathOther;
            LocGraph.DrawLine(p, (float)LastX , (float)LastY, (float)x, (float)y);
            LastX = x; LastY = y;
        }

        private void DrawVehicleHeight(int WhichStep)
        {
            if (WhichStep >= NoOfLogEntries) return;
            double Alt = lpi[WhichStep].GPSAlt - Lowest;
            Alt = Alt * ScaleEl;
            Alt = PBLocation.Size.Height - Alt;
            Pen p9 = new Pen(PBLocation.BackColor, 6);
            float xl = PBLocation.Size.Width-3;
            LocGraph.DrawLine(p9, xl, PBLocation.Size.Height - 0, xl, 0f);
            LocGraph.DrawLine(PenVehicleHeight, xl, (float)PBLocation.Size.Height, xl, (float)Alt);

        }
        private void DrawVehicleLocation(int WhichStep)
        {
            if (WhichStep >= NoOfLogEntries) return;
            double x, y;
            x = Math.Round((lpi[WhichStep].Lon - Westest) * ScaleX + 1);
            y = Math.Round((Northest - lpi[WhichStep].Lat) * ScaleY + 1);
            DrawVehicleHeight(WhichStep);
            DrawVehicle((int)x, (int)y);
        }
        const int VLen = 8;
        int LastVX = 0, LastVY = 0;
        Pen PenVehicle = new Pen(Color.Black, 2);
        private void DrawVehicle(int x, int y)
        {
            if (LastVY == 0)
            {
                LastVY = 0;
            }
            if (LastVX != 0 || LastVY != 0)
            {//erase last
                MyUtils.GDI.DrawXORLine(LocGraph, PenVehicle, LastVX, LastVY - VLen, LastVX, LastVY + VLen);
                MyUtils.GDI.DrawXORLine(LocGraph, PenVehicle, LastVX - VLen, LastVY, LastVX + VLen, LastVY);
            }
            MyUtils.GDI.DrawXORLine(LocGraph, PenVehicle, (int)x, (int)y - VLen, (int)x, (int)y + VLen);
            MyUtils.GDI.DrawXORLine(LocGraph, PenVehicle, (int)x - VLen, (int)y, (int)x + VLen, (int)y);
            LastVX = x; LastVY = y;
        }
        bool GetCurrLineData(String LogLine, ref LogPointInfo lpi)
        {
            string delimStr = ",";
            LogLine = LogLine.Replace(" ", "");
            char[] delimiter = delimStr.ToCharArray();
            string[] split;
            if (LogLine.IndexOf("CURR,") >= 0)
            {
                delimiter = delimStr.ToCharArray();
                split = LogLine.Split(delimiter);
                if (split.Length >= 5)
                {
                    try
                    {
                        lpi.CurrThrottleIn = MyUtils.ConvertToDouble(split[1]) / 1.0;
                        lpi.CurrThrottleTotal = MyUtils.ConvertToDouble(split[2]) / 1.0;
                        lpi.CurrVoltage = MyUtils.ConvertToDouble(split[3]) / 1.0;
                        lpi.CurrCurrent = MyUtils.ConvertToDouble(split[4]) / 1.0;
                        lpi.CurrCurrentTotal = MyUtils.ConvertToDouble(split[5]) / 1.0;
                        return true;
                    }
                    catch
                    {
                        BadLines += LogLine + "\r\n" ;
                        BadLinesInLogFile++;
                        return false;
                    }
                }
                else
                {
                    BadLines += LogLine + "\r\n";
                    BadLinesInLogFile++;
                    return false;
                }
            }
            return false;
        }
        bool GetNTunLineData(String LogLine, ref LogPointInfo lpi)
        {
            string delimStr = ",";
            LogLine = LogLine.Replace(" ", "");
            char[] delimiter = delimStr.ToCharArray();
            string[] split;
            if (LogLine.IndexOf("NTUN,") >= 0)
            {
                delimiter = delimStr.ToCharArray();
                split = LogLine.Split(delimiter);
                if (split.Length >= 10)
                {
                    try
                    {
                        lpi.NTunWPDist = MyUtils.ConvertToDouble(split[1]) / 1.0;
                        lpi.NTunTargetBearing = MyUtils.ConvertToDouble(split[2]) / 1.0;
                        lpi.NTunLonErr = MyUtils.ConvertToDouble(split[3]) / 1.0;
                        lpi.NTunLatErr = MyUtils.ConvertToDouble(split[4]) / 1.0;
                        lpi.NTunNavLon = MyUtils.ConvertToDouble(split[5]) / 1.0;
                        lpi.NTunNavLat = MyUtils.ConvertToDouble(split[6]) / 1.0;
                        lpi.NTunXSpeed = MyUtils.ConvertToDouble(split[7]) / 1.0;
                        lpi.NTunYSpeed = MyUtils.ConvertToDouble(split[8]) / 1.0;
                        lpi.NTunNavLonI = MyUtils.ConvertToDouble(split[9]) / 1.0;
                        lpi.NTunNavLatI = MyUtils.ConvertToDouble(split[10]) / 1.0;
                        return true;
                    }
                    catch
                    {
                        BadLines += LogLine + "\r\n";
                        BadLinesInLogFile++;
                        return false;
                    }
                }
                else
                {
                    BadLines += LogLine + "\r\n";
                    BadLinesInLogFile++;
                    return false;
                }
            }
            return false;
        }
        bool GetPMLineData(String LogLine, ref LogPointInfo lpi)
        {
            string delimStr = ",";
            LogLine = LogLine.Replace(" ", "");
            char[] delimiter = delimStr.ToCharArray();
            string[] split;
            if (LogLine.IndexOf("PM,") >= 0)
            {
                delimiter = delimStr.ToCharArray();
                split = LogLine.Split(delimiter);
                if (split.Length >= 4)
                {
                    try
                    {
                        lpi.GyroSaturation = MyUtils.ConvertToDouble(split[1]) / 1.0;
                        lpi.ADCConstraints = MyUtils.ConvertToDouble(split[2]) / 1.0;
                        lpi.DCMRenorms = MyUtils.ConvertToDouble(split[3]) / 1.0;
                        lpi.DCMBlowUps = MyUtils.ConvertToDouble(split[4]) / 1.0;
                        lpi.GPSFixCount = MyUtils.ConvertToDouble(split[4]) / 1.0; //not sure which is right, 4 or 5.  I think it should be 5, but doesn't work.
                        return true;
                    }
                    catch
                    {
                        BadLines += LogLine + "\r\n";
                        BadLinesInLogFile++;
                        return false;
                    }
                }
                else
                {
                    BadLines += LogLine + "\r\n";
                    BadLinesInLogFile++;
                    return false;
                }
            }
            return false;
        }

        bool GetCTunLineData(String LogLine, ref LogPointInfo lpi)
        {
            string delimStr = ",";
            LogLine = LogLine.Replace(" ", "");
            char[] delimiter = delimStr.ToCharArray();
            string[] split;
            if (LogLine.IndexOf("CTUN,") >= 0)
            {
                delimiter = delimStr.ToCharArray();
                split = LogLine.Split(delimiter);
                if (split.Length >= 11)
                {
                    try
                    {
                        lpi.CTunThrotIn = MyUtils.ConvertToDouble(split[1]) / 1.0;
                        lpi.CTunSonarAlt = MyUtils.ConvertToDouble(split[2]) / 1.0;
                        lpi.CTunBaroAlt = MyUtils.ConvertToDouble(split[3]) / 1.0;
                        lpi.CTunWPAlt = MyUtils.ConvertToDouble(split[4]) / 1.0;
                        lpi.CTunNavThrottle = MyUtils.ConvertToDouble(split[5]) / 1.0;
                        lpi.CTunAngleBoost = MyUtils.ConvertToDouble(split[6]) / 1.0;
//2.6 CTun....                        CTUN, 505, 209, 1003, 1073, 26,  0, 0, 20, 536, 13, 13
//2.7 CTun                            CTUN, 563,  72,   77, 3305,  0, 10, 0, 56, 579,  0


                        if (split.Length == 12)
                        {
                            lpi.CTunManualBoost = MyUtils.ConvertToDouble(split[7]) / 1.0;
                            lpi.CTunClimbRate = MyUtils.ConvertToDouble(split[8]) / 1.0;
                            lpi.CTunRC3ServoOut = MyUtils.ConvertToDouble(split[9]) / 1.0;
                            lpi.CTunAltHoldInt = MyUtils.ConvertToDouble(split[10]) / 1.0;
                            lpi.CTunThrottleInt = MyUtils.ConvertToDouble(split[11]) / 1.0;
                        }
                        else
                        {
                            lpi.CTunManualBoost = 0;
                            lpi.CTunClimbRate = MyUtils.ConvertToDouble(split[7]) / 1.0;
                            lpi.CTunRC3ServoOut = MyUtils.ConvertToDouble(split[8]) / 1.0;
                            lpi.CTunAltHoldInt = MyUtils.ConvertToDouble(split[9]) / 1.0;
                            lpi.CTunThrottleInt = MyUtils.ConvertToDouble(split[10]) / 1.0;
                        }
                        return true;
                    }
                    catch
                    {
                        BadLinesInLogFile++;
                        BadLines += LogLine + "\r\n";
                        return false;
                    }
                }
                else
                {
                    BadLines += LogLine + "\r\n";
                    BadLinesInLogFile++;
                    return false;
                }
            }
            return false;
        }
        private bool GetATTLineData(String LogLine, ref LogPointInfo lpi)
        {
            string delimStr = ",";
            LogLine = LogLine.Replace(" ", "");
            char[] delimiter = delimStr.ToCharArray();
            string[] split;
            if (LogLine.IndexOf("ATT,") >= 0)
            {
                delimiter = delimStr.ToCharArray();
                split = LogLine.Split(delimiter);
                if (split.Length >= 8)
                {
                    try
                    {
                        lpi.RollIN = MyUtils.ConvertToDouble(split[1]) / 100.0;
                        lpi.Roll = MyUtils.ConvertToDouble(split[2]) / 100.0;
                        lpi.PitchIN = MyUtils.ConvertToDouble(split[3]) / 100.0;
                        lpi.Pitch = MyUtils.ConvertToDouble(split[4]) / 100.0;
                        lpi.YawIN = MyUtils.ConvertToDouble(split[5]) / 100.0;
                        lpi.Yaw = MyUtils.ConvertToDouble(split[6]) / 100.0;
                        lpi.MagHeading = MyUtils.ConvertToDouble(split[7]) / 100.0;
                        return true;
                    }
                    catch
                    {
                        BadLines += LogLine + "\r\n";
                        BadLinesInLogFile++;
                        return false;
                    }
                }
                else
                {
                    BadLines += LogLine + "\r\n";
                    BadLinesInLogFile++;
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        private bool GetMotLineData(String LogLine, ref LogPointInfo lpi)
        {
            string delimStr = ",";
            LogLine = LogLine.Replace(" ", "");
            char[] delimiter = delimStr.ToCharArray();

            if (LogLine.IndexOf("MOT,") >= 0)
            {
                delimiter = delimStr.ToCharArray();
                string[] split = LogLine.Split(delimiter);
                if (split.Length >= 4)
                {
                    try
                    {
                        lpi.Mot1 = MyUtils.ConvertToDouble(split[1]);
                        lpi.Mot2 = MyUtils.ConvertToDouble(split[2]);
                        lpi.Mot3 = MyUtils.ConvertToDouble(split[3]);
                        lpi.Mot4 = MyUtils.ConvertToDouble(split[4]);
                        return true;
                    }
                    catch
                    {
                        BadLines += LogLine + "\r\n";
                        BadLinesInLogFile++;
                        return false;
                    }
                }
                else
                {
                    BadLines += LogLine + "\r\n";
                    BadLinesInLogFile++;
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        private bool GetCMDLineData(String LogLine, ref LogPointInfo lpi)
        {
            string delimStr = ",";
            LogLine = LogLine.Replace(" ", "");
            char[] delimiter = delimStr.ToCharArray();
            lpi.CMDTotal = 0;
            lpi.CMDCurrentNum = 0;
            lpi.CMDID = 0;
            lpi.CMDOptions = 0;
            lpi.CMDP1 = 0;
            lpi.CMDAlt = 0;
            lpi.CMDLat = 0;
            lpi.CMDLon = 0;
            if (LogLine.IndexOf("CMD,") >= 0)
            {
                delimiter = delimStr.ToCharArray();
                string[] split = LogLine.Split(delimiter);
                if (split.Length >= 4)
                {
                    try
                    {
                        lpi.CMDTotal = Convert.ToInt32(split[1]);
                        lpi.CMDCurrentNum = Convert.ToInt32(split[2]);
                        lpi.CMDID = Convert.ToInt32(split[3]);
                        if (split.Length > 4) lpi.CMDOptions = Convert.ToInt32(split[4]);
                        if (split.Length > 5) lpi.CMDP1 = Convert.ToInt32(split[5]);

                        if (split.Length > 6) lpi.CMDAlt = MyUtils.ConvertToDouble(split[6]) / 100.0;
                        if (split.Length > 7) lpi.CMDLat = MyUtils.ConvertToDouble(split[7]) / 10000000.0;
                        if (split.Length > 8) lpi.CMDLon = MyUtils.ConvertToDouble(split[8]) / 10000000.0;
                        return true;
                    }
                    catch
                    {
                        return false;
                    }
                }
                else return false;
            }
            else
            {
                return false;
            }
        }
        const int MaxAvg = 5;
        int BadLinesInLogFile = 0;
        String BadLines = "";
        double[] AvgLat = new double[MaxAvg];
        double[] AvgLon = new double[MaxAvg];
        double[] AvgAlt = new double[MaxAvg];
        double DeviationMaxDegs = 2.0 * MyUtils.Klicks2Degs;
        double DeviationMaxAlt = 200.0;
        int AvgPtr = 0;
        bool FirstReading = false;
        private bool GetGPSLineData(String GPSLine, ref LogPointInfo lpix, int which)
        {
            string delimStr = ",";
            GPSLine = GPSLine.Replace(" ", "");
            char[] delimiter = delimStr.ToCharArray();

            if (GPSLine.IndexOf("GPS,") >= 0)
            {
                delimiter = delimStr.ToCharArray();
                string[] split = GPSLine.Split(delimiter);
                if (split.Length >= 9)
                {
                    try
                    {
                        lpix.mSecs = Convert.ToInt32(split[1]);

                        lpix.Sats = Convert.ToInt32(split[2]);
                        lpix.Lat = MyUtils.ConvertToDouble(split[3]);
                        lpix.Lon = MyUtils.ConvertToDouble(split[4]);
                        lpix.MixAlt = MyUtils.ConvertToDouble(split[5]);
                        lpix.GPSAlt = MyUtils.ConvertToDouble(split[6]);
                        lpix.GRSpeed = MyUtils.ConvertToDouble(split[7]);
                        lpix.CRS = MyUtils.ConvertToDouble(split[8]);
                        AvgLat[AvgPtr] = lpix.Lat;
                        AvgLon[AvgPtr] = lpix.Lon;
                        AvgAlt[AvgPtr] = lpix.GPSAlt;
                        if (FirstReading == false)
                        {
                            FirstReading = true;
                            for (int i = 0; i < MaxAvg; i++)
                            {
                                AvgLat[i] = lpix.Lat;
                                AvgLon[i] = lpix.Lon;
                                AvgAlt[i] = lpix.GPSAlt;
                            }
                        }
                        if (AvgPtr < MaxAvg-1) AvgPtr++; else AvgPtr = 0;
                        double AvAlt = GetAvg(AvgAlt, MaxAvg);
                        double AvLat = GetAvg(AvgLat, MaxAvg);
                        double AvLon = GetAvg(AvgLon, MaxAvg);
                        if ( Math.Abs(AvLat - lpix.Lat) > DeviationMaxDegs || Math.Abs(AvLon - lpix.Lon) > DeviationMaxDegs || Math.Abs(AvAlt - lpix.GPSAlt) > DeviationMaxAlt )
                        {
                            BadLinesInLogFile++;
                            if (which > 1)
                            {
                                BadLines += GPSLine + "\r\n";

                                CopyGPSLogPointInfo(lpix, lpi[which - 1]);
                            }
                            return false;
                        }
//                        StreamWriter sw = new StreamWriter("C:\\GPS.txt", true);
  //                      sw.WriteLine(GPSLine);
    //                    sw.Close();
                        return true;
                    }
                    catch
                    {
                        BadLines += GPSLine + "\r\n";
                        BadLinesInLogFile++;
                        if (which > 1)
                        {
                            CopyGPSLogPointInfo(lpix, lpi[which - 1]);
                        }
                        return false;
                    }
                }
                else
                {
                    BadLines += GPSLine + "\r\n";
                    BadLinesInLogFile++;
                    if (which > 1)
                    {
                        CopyGPSLogPointInfo(lpix, lpi[which - 1]);
                    }
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        private double GetAvg(double[] AvgArr, int cnt)
        {
            double sum = 0;
            for(int i = 0; i < cnt; i++)
            {
                sum += AvgArr[i];
            }
            return sum / cnt;
        }

        private void UpdateLabels()
        {
            int pt=(int) TrBCurStep.Value;
            if (pt > NoOfLogEntries-1) pt = NoOfLogEntries-1;
            if (lpi == null) return;
            LBGPSUT.Text = "GPS UnivTime=" + MyUtils.MSecsSince0UTToUT(lpi[pt].mSecs);
            LBGPSLT.Text = "GPS LocTime=" + MyUtils.MSecsSince0UTToLT(lpi[pt].mSecs);
            
            LBSats.Text = "GPSSats=" + lpi[pt].Sats.ToString();
            LBLat.Text = "Latitude=" + lpi[pt].Lat.ToString();
            LBLon.Text = "Longitude=" + lpi[pt].Lon.ToString();
            LBGPSAlt.Text = "AbsAlt=" + lpi[pt].GPSAlt.ToString();
            LBRelAlt.Text = "MixAlt=" + (Math.Round((lpi[pt].MixAlt),1)).ToString() ;
            LBGPSSPeed.Text = "GPSSpeed=" + lpi[pt].GRSpeed.ToString();
            LBCRS.Text = "GPSCRS=" + lpi[pt].CRS.ToString();

            LBRoll.Text = "Roll=" + lpi[pt].Roll.ToString(); LBPitch.Text = "Pitch=" + lpi[pt].Pitch.ToString();
            LBYaw.Text = "Yaw=" + lpi[pt].Yaw.ToString();
            LBMot1.Text = "Mot1=" + lpi[pt].Mot1.ToString();
            LBMot2.Text = "Mot2=" + lpi[pt].Mot2.ToString();
            LBMot3.Text = "Mot3=" + lpi[pt].Mot3.ToString();
            LBMot4.Text = "Mot4=" + lpi[pt].Mot4.ToString();
            LBMagHead.Text = "MagHead=" + lpi[pt].MagHeading.ToString();
            LBCurMode.Text = "CurMode=" + MyUtils.GetMode(lpi[pt].Mode);

            LBVolts.Text = "Volts=" + lpi[pt].CurrVoltage.ToString();
            LBAmps.Text = "Amps=" + lpi[pt].CurrCurrent.ToString();
            LBAmpsTotal.Text = "AmpsTot=" + lpi[pt].CurrCurrentTotal.ToString();
            LBThrot.Text = "Thot=" + lpi[pt].CurrThrottleIn.ToString();


            LBNTunWPDist.Text = "WPDist=" + lpi[pt].NTunWPDist.ToString();
            LBNTTargetBearing.Text = "TargBer=" + lpi[pt].NTunTargetBearing.ToString();
            LBNTLonErr.Text = "LonErr=" + lpi[pt].NTunLonErr.ToString();
            LBNTLatErr.Text = "LatErr=" + lpi[pt].NTunLatErr.ToString();
            LBNTNavLon.Text = "NvLon=" + lpi[pt].NTunNavLon.ToString();
            LBNTNavLat.Text = "NvLat=" + lpi[pt].NTunNavLat.ToString();
            LBNTXSpeed.Text = "XSped=" + lpi[pt].NTunXSpeed.ToString();
            LBNTYSpeed.Text = "YSped=" + lpi[pt].NTunYSpeed.ToString();
            LBNTNavLatI.Text = "NvLatI=" + lpi[pt].NTunNavLatI.ToString();
            LBNTNavLonI.Text = "NvLonI=" + lpi[pt].NTunNavLonI.ToString();

            LBCTThrotIn.Text = "ThrotIn=" + lpi[pt].CTunThrotIn.ToString();
            LBCTSonarAlt.Text = "SonarAlt=" + lpi[pt].CTunSonarAlt.ToString();
            LBCTBaroAlt.Text = "BaroAlt=" + lpi[pt].CTunBaroAlt.ToString();
            LBCTWPAlt.Text = "WPAlt=" + lpi[pt].CTunWPAlt.ToString();
            LBCTNavThrot.Text = "NavThrot=" + lpi[pt].CTunNavThrottle.ToString();
            LBCTAngBoost.Text = "AngBoost=" + lpi[pt].CTunAngleBoost.ToString();
            LBCTunManBoost.Text = "ManBoost=" + lpi[pt].CTunManualBoost.ToString();
            LBCTClimbRate.Text = "ClimbRate=" + lpi[pt].CTunClimbRate.ToString();
            LBCTRC3Out.Text = "RC3SrvOut=" + lpi[pt].CTunRC3ServoOut.ToString();
            LBCTAltHoldI.Text = "AltHoldInt=" + lpi[pt].CTunAltHoldInt.ToString();
            LBCTThrotI.Text = "ThrotInt=" + lpi[pt].CTunThrottleInt.ToString();

            String cs = "CMD No.=" + lpi[pt].CMDCurrentNum.ToString();
            cs += " CMD=" + GetCommandString(lpi[pt].CMDID);
            cs += " Options=" + lpi[pt].CMDOptions.ToString();
            cs += " Parm1=" + lpi[pt].CMDP1.ToString();
            String cs1 = " Lat=" + lpi[pt].CMDLat.ToString();
            cs1 += " Lon=" + lpi[pt].CMDLon.ToString();
            cs1 += " Alt=" + lpi[pt].CMDAlt.ToString();

            LBCommand.Text = cs;
            LBCommand1.Text = cs1;

            if (!InCopterPaint)
            {
                DrawCopters.DrawBirdsEyeView(LayoutGraph, PBCopters.Size.Width - 70, PBCopters.Size.Height / 2, 100, lpi[pt].Yaw);
                DrawCopters.DrawCopterRollView(LayoutGraph, 50, PBCopters.Size.Height / 2, 100, (float)lpi[pt].Roll);
                DrawCopters.DrawCopterPitchView(LayoutGraph, 170, PBCopters.Size.Height / 2, 100, (float)lpi[pt].Pitch);
            }
        }
        private String GetCommandString(int cmd)
        {
            return IntToCommand(cmd);
        }
        private void TrBCurStep_Scroll(object sender, EventArgs e)
        {
            DoStep(0);
        }
        private void DoStep(int WhichStep)
        {
            if (WhichStep != 0)
            {
                TrBCurStep.Value = WhichStep;
            }
            LBCurStep.Text = "Log Pointer Slider. CurrentStep=" + (TrBCurStep.Value).ToString();
            DrawVehicleLocation((int)TrBCurStep.Value);
            UpdateLabels();
            DatGraf.IndexInto = (int)TrBCurStep.Value;

        }

        private void BTPlayLogFwd_Click(object sender, EventArgs e)
        {
            PlayFwd = true;
            PlayRev = false;
        }

        private void BTPlayLogRev_Click(object sender, EventArgs e)
        {
            PlayRev = true;
            PlayFwd = false;
        }
        int DesiredStep = 0;
        void DoCopterPaint()
        {

            //       e.Graphics.Clear(PBCopters.BackColor);
            LayoutGraph.Clear(PBCopters.BackColor);
            DrawCopters.lastAngleBEVDegs = -2222;
            DrawCopters.LastBEVAngle = -2222;
            DrawCopters.lastAngleRollDegs = -2222;
            DrawCopters.LastRollAngle = -2222;
            DrawCopters.lastAnglePitchDegs = -2222;
            DrawCopters.LastPitchAngle = -2222;
            //          DoStep(0);
            paintCnt++;
        }
        int LastIntoArray = 0;
        private void LogTimer_Tick(object sender, EventArgs e)
        {

            if (DoLocationPaint) { DoLocationPaint = false; LastX = LastY = 0; DisplayFlightPath(); LastVY = LastVX = 0; DrawVehicleLocation((int)TrBCurStep.Value); }
            if (StartUpDoLog) { StartUpDoLog = false;  DoTheLogFile(); return; }
            if (!InLoadFile) InLoadFileCnt++;
            DoLabelColors();
            if (DoCopterPnt) { DoCopterPnt = false; DoCopterPaint(); }
            if (PlayFwd && !MouDownInTrackBar)
            {
                BTPlayLogFwd.BackColor = Color.LightSeaGreen;
                BTPlayLogRev.BackColor = BTLoadFile.BackColor;
                DesiredStep += TrBPlaySpeed.Value;
            }
            else if (PlayRev && !MouDownInTrackBar)
            {
                BTPlayLogFwd.BackColor = BTLoadFile.BackColor;
                BTPlayLogRev.BackColor = Color.LightSeaGreen;
                DesiredStep -= TrBPlaySpeed.Value;
                if (DesiredStep <= 0)
                {
                    DesiredStep = 0;
                    PlayRev = false;
                }
            }
            else if ((PlayRev || PlayFwd) && MouDownInTrackBar)
            {
                DesiredStep = TrBCurStep.Value;
            }
            else
            {
                DesiredStep = TrBCurStep.Value;
                BTPlayLogFwd.BackColor = BTLoadFile.BackColor;
                BTPlayLogRev.BackColor = BTLoadFile.BackColor;
                if (DatGraf != null && DatGraf.EG != null)
                {
                    if (LastIntoArray != DatGraf.EG.MouseIntoArray)
                    {
                        DesiredStep = LastIntoArray = DatGraf.EG.MouseIntoArray;
                    }
                }
            }
            if (DesiredStep < NoOfLogEntries - 1 && DesiredStep < TrBCurStep.Maximum)
            {
                if(PlayRev || PlayFwd) DoStep(DesiredStep);
            }
            else
            {
                DesiredStep = NoOfLogEntries-1;
                PlayFwd = false;
            }
            if (DesiredStep < 0)
            {
                DesiredStep = 0;
                PlayRev = false;
            }
            else if( !(PlayFwd || PlayRev)) 
            {
                DoStep(DesiredStep);
            }
        }
        bool PlayFwd = false;
        bool PlayRev = false;
        private void TrBPlaySpeed_Scroll(object sender, EventArgs e)
        {

        }

        private void BTPause_Click(object sender, EventArgs e)
        {
            PlayFwd = PlayRev = false;
        }
        class DrawCopters
        {
            static Pen BirdsEyePen = new Pen(Color.DarkMagenta, 2);
            internal static double lastAngleBEVDegs = -2222;
            internal static double lastAngleRollDegs = -2222;
            internal static double lastAnglePitchDegs = -2222;
            internal static float LastBEVAngle = -2222;
            internal static float LastRollAngle = -2222;
            internal static float LastPitchAngle = -2222;
            static internal void DrawCopterPitchView(Graphics LayoutGraph, float OffsetX, float OffsetY, float Width, float AngleDegs)
            {
                if (LayoutGraph == null) return;
                if (AngleDegs == lastAnglePitchDegs) return;
                lastAnglePitchDegs = AngleDegs;
                float Angle = (float)(AngleDegs * MyUtils.D2R);
                if (LastPitchAngle < -1111)
                    DrawCopterPitch(LayoutGraph, OffsetX, OffsetY, Width, Angle);
                else
                {
                    DrawCopterPitch(LayoutGraph, OffsetX, OffsetY, Width, LastPitchAngle); //erase last
                    DrawCopterPitch(LayoutGraph, OffsetX, OffsetY, Width, Angle);
                }
                LastPitchAngle = Angle;
            }
            static void DrawCopterPitch(Graphics LayoutGraph, float OffsetX, float OffsetY, float Width, float AngleRads)
            {
                float propellerSize = Width * (float)0.25;
                float ArmLen = Width * 0.5f;
                AngleRads = 0 - AngleRads;
                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, -ArmLen, 0, ArmLen, 0, AngleRads);

                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, -ArmLen + propellerSize / 2, 0, -ArmLen + propellerSize / 2, -propellerSize / 2, AngleRads);
                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, -ArmLen, -propellerSize / 2, -ArmLen + propellerSize, -propellerSize / 2, AngleRads);

                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, ArmLen - propellerSize / 2, 0, ArmLen - propellerSize / 2, -propellerSize / 2, AngleRads);
                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, ArmLen, -propellerSize / 2, ArmLen - propellerSize, -propellerSize / 2, AngleRads);

                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, -ArmLen, 3, ArmLen, 3, AngleRads);

                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, -propellerSize / 2, 3, -ArmLen + (propellerSize / 2), 20, AngleRads);
                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, propellerSize / 2, 3, ArmLen - (propellerSize / 2), 20, AngleRads);

                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, ArmLen + 2,  1, ArmLen - (propellerSize / 3), -6, AngleRads);
                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, ArmLen + 2, 1, ArmLen - (propellerSize / 3), 9, AngleRads);

            }
            static void DrawCopterRoll(Graphics LayoutGraph, float OffsetX, float OffsetY, float Width, float AngleRads)
            {

                float propellerSize = Width * (float)0.25;
                float ArmLen = Width * 0.5f;
                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, -ArmLen, 0, ArmLen, 0, AngleRads);

                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, -ArmLen + propellerSize / 2, 0, -ArmLen + propellerSize / 2, -propellerSize / 2,   AngleRads);
                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, -ArmLen, -propellerSize / 2, -ArmLen + propellerSize , -propellerSize / 2, AngleRads);

                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, ArmLen - propellerSize / 2, 0, ArmLen - propellerSize / 2, -propellerSize / 2, AngleRads);
                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, ArmLen, -propellerSize / 2, ArmLen - propellerSize, -propellerSize / 2, AngleRads);

                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, -ArmLen, 3, ArmLen, 3, AngleRads);

                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, -propellerSize/2, 3, -ArmLen + (propellerSize/2), 20, AngleRads);
                DrawXorLine(LayoutGraph, BirdsEyePen, OffsetX, OffsetY, propellerSize / 2, 3, ArmLen - (propellerSize / 2), 20, AngleRads);

            }
            static void DrawXorLine(Graphics LayG, Pen p, float CenterX, float CenterY, float StartX, float StartY, float FinishX, float FinishY, float AngleRads)
            {
                float xLen = StartX;
                float yLen = StartY;
                float xNewStart = 0; float yNewStart = 0;
                RotateXY(AngleRads, StartX, StartY, ref xNewStart, ref yNewStart);

                xLen = FinishX;
                yLen = FinishY;
                float xNewFinish = 0; float yNewFinish = 0;
                RotateXY(AngleRads, FinishX, FinishY, ref xNewFinish, ref yNewFinish);
//                RotateXY(22 * (float) MyUtils.D2R, 4.209f, 1.362f, ref xNewFinish, ref yNewFinish);

                xNewStart = (float) Math.Round(xNewStart);yNewStart = (float)Math.Round(yNewStart);
                xNewFinish = (float)Math.Round(xNewFinish); yNewFinish = (float)Math.Round(yNewFinish);
                if (StartX < 0)
                {
                    xNewStart = 0 - xNewStart;
                    yNewStart = 0 - yNewStart;
                }
                if (FinishX < 0)
                {
                    xNewFinish = 0 - xNewFinish;
                    yNewFinish = 0 - yNewFinish;
                }

                MyUtils.GDI.DrawXORLine(LayG, p, (int)xNewStart + (int)CenterX, (int)yNewStart + 
                    (int)CenterY, (int)xNewFinish + (int)CenterX, (int)yNewFinish + (int)CenterY);
            }
            static void RotateXY(float RotAngleRads, float InX, float InY, ref float OutX, ref float OutY)
            {
                //first we find the angle if rotation is 0.
                double Angle = 0.0;
                if(InX != 0) Angle = Math.Atan((double)InY / (double)InX);
                double Radius = Math.Sqrt((double)(InX * InX) + (double) (InY * InY));
                //if (InX < 0 && InY >= 0) Radius = 0 - Radius;
                //else if (InY < 0 && InX >= 0) Radius = 0 - Radius;
                Angle += RotAngleRads;
                if (Angle > MyUtils.PT2) Angle -= MyUtils.PT2;
                if (Angle < 0.0) Angle += MyUtils.PT2;
                OutX = (float) Math.Cos(Angle) * (float) Radius;
                OutY = (float)Math.Sin(Angle) * (float) Radius;
//                if (InX < 0) { OutX = 0 - OutX; OutY = 0 - OutY; }
  //              if (InY < 0) { OutY = 0 - OutY; OutX = 0 - OutX; }
            }

            static internal void DrawCopterRollView(Graphics LayoutGraph, float OffsetX, float OffsetY, float Width, float AngleDegs)
            {
                if (LayoutGraph == null) return;
                if (AngleDegs == lastAngleRollDegs) return;
                lastAngleRollDegs = AngleDegs;
                float Angle = (float)(AngleDegs * MyUtils.D2R);
                if (LastRollAngle < -1111)
                    DrawCopterRoll(LayoutGraph, OffsetX, OffsetY, Width, Angle);
                else
                {
                    DrawCopterRoll(LayoutGraph, OffsetX, OffsetY, Width, LastRollAngle); //erase last
                    DrawCopterRoll(LayoutGraph, OffsetX, OffsetY, Width, Angle);
                }
                LastRollAngle = Angle;
            }
            static internal void DrawBirdsEyeView(Graphics LayoutGraph, float OffsetX, float OffsetY, float Width, double AngleDegs)
            {
                if (LayoutGraph == null) return;
                if (AngleDegs == lastAngleBEVDegs) return;
                lastAngleBEVDegs = AngleDegs;
                float Angle = (float)((AngleDegs - 45) * MyUtils.D2R);
                if (LastBEVAngle < -1111)
                    DrawCopterBEV(LayoutGraph, OffsetX, OffsetY, Width, Angle);
                else
                {
                    DrawCopterBEV(LayoutGraph, OffsetX, OffsetY, Width, LastBEVAngle); //erase last
                    DrawCopterBEV(LayoutGraph, OffsetX, OffsetY, Width, Angle);
                }
                LastBEVAngle = Angle;
            }
            static Pen PenNums = new Pen(Color.Black, 1);
            static internal void DrawXORNum(Graphics g, int num, int x, int y)
            {
                const int width = 8;
                int xl, yl, xm, ym;
                const int height = 12;
                Pen p = PenNums;
                switch (num)
                {
                    case 0:
                        MyUtils.GDI.DrawXOREllipse(g, p, x - width / 2, y - height / 2, x + width / 2, y + height / 2);
                        break;
                    case 1:
                        xl = (x - width / 2) + (width / 4); yl = (y - height / 2) + height / 4;
                        xm = x; ym = (y - height / 2);
                        MyUtils.GDI.DrawXORLine(g, p, xl, yl, xm, ym);
                        xl = xm; yl = y + height / 2;
                        MyUtils.GDI.DrawXORLine(g, p, xm, ym, xl, yl);
                        xl = (x - width / 2); yl = (y - height / 2) + height;
                        xm = (x + width / 2); ym = (y - height / 2) + height;
                        MyUtils.GDI.DrawXORLine(g, p, xl, yl, xm, ym);
                        break;
                    case 2:
                        xl = x - width / 4; yl = y - height / 2;
                        MyUtils.GDI.DrawXORLine(g, p, x - width / 2, (y - height / 2) + height / 4, xl, yl);
                        xm = x + width / 4; ym = y - height / 2;
                        MyUtils.GDI.DrawXORLine(g, p, xl, yl, xm, ym);
                        xl = x + width / 4; yl = (y - height / 2) + height / 4;
                        MyUtils.GDI.DrawXORLine(g, p, xm, ym, xl, yl);
                        xm = x - width / 2; ym = y - height / 2 + height;
                        MyUtils.GDI.DrawXORLine(g, p, xl, yl, xm, ym);
                        xl = x + width / 2; yl = (y - height / 2) + height;
                        MyUtils.GDI.DrawXORLine(g, p, xm, ym, xl, yl);
                        break;
                    case 3:
                        xl = x - width / 4; yl = y - height / 2;
                        MyUtils.GDI.DrawXORLine(g, p, x - width / 2, (y - height / 2) + height / 4, xl, yl);
                        xm = x + width / 4; ym = y - height / 2;
                        MyUtils.GDI.DrawXORLine(g, p, xl, yl, xm, ym);
                        xl = x + width / 4; yl = (y - height / 2) + height / 4;
                        MyUtils.GDI.DrawXORLine(g, p, xm, ym, xl, yl);
                        xm = x; ym = y;
                        MyUtils.GDI.DrawXORLine(g, p, xl, yl, xm, ym);
                        xl = x + width / 2; yl = y + height / 4;
                        MyUtils.GDI.DrawXORLine(g, p, xm, ym, xl, yl);
                        xm = xl; ym = yl + height / 6;
                        MyUtils.GDI.DrawXORLine(g, p, xl, yl, xm, ym);
                        xl = x + width / 4; yl = y + height / 2;
                        MyUtils.GDI.DrawXORLine(g, p, xm, ym, xl, yl);
                        xm = x - width / 4; ym = yl;
                        MyUtils.GDI.DrawXORLine(g, p, xl, yl, xm, ym);
                        xl = x - width / 2; yl = (y + height / 2) - height / 4;
                        MyUtils.GDI.DrawXORLine(g, p, xm, ym, xl, yl);
                        break;
                    case 4:
                        xm = x; ym = y + height / 2;
                        xl = x; yl = y - height / 2;
                        MyUtils.GDI.DrawXORLine(g, p, xm, ym, xl, yl);
                        xm = x - width / 2; ym = y;
                        MyUtils.GDI.DrawXORLine(g, p, xl, yl, xm, ym);
                        xl = x + width / 2; yl = y;
                        MyUtils.GDI.DrawXORLine(g, p, xm, ym, xl, yl);
                        break;
                }
            }

            static void DrawCopterBEV(Graphics LayoutGraph, float OffsetX, float OffsetY, float Width, float AngleRads)
            {
                int x1 = 1, y1 = 1, x2 = 1, y2 = 1;
                
                float propellerSize = Width * (float)0.15;
                x1 = (int)Math.Round(OffsetX - propellerSize);
                x2 = (int)Math.Round(OffsetX + propellerSize);
                y1 = (int)Math.Round(OffsetY - propellerSize);
                y2 = (int)Math.Round(OffsetY + propellerSize);
                MyUtils.GDI.DrawXOREllipse(LayoutGraph, BirdsEyePen, x1, y1, x2, y2);

                float ArmLen = Width * 0.5f;
                float xx = ArmLen * (float)Math.Cos(AngleRads);
                float yy = ArmLen * (float)Math.Sin(AngleRads);

                x1 = (int)Math.Round(OffsetX - propellerSize + xx);
                x2 = (int)Math.Round(OffsetX + propellerSize + xx);
                y1 = (int)Math.Round(OffsetY - propellerSize + yy);
                y2 = (int)Math.Round(OffsetY + propellerSize + yy);
                MyUtils.GDI.DrawXOREllipse(LayoutGraph, BirdsEyePen, x1, y1, x2, y2);
                MyUtils.GDI.DrawXORLine(LayoutGraph, BirdsEyePen, (int)OffsetX, (int)OffsetY,
                    (int)(OffsetX + (float)Math.Round(xx)), (int)(OffsetY + (float)Math.Round(yy)));
                DrawXORNum(LayoutGraph, 1, (int)(OffsetX + (float)Math.Round(xx)), (int)(OffsetY + (float)Math.Round(yy)));

                x1 = (int)Math.Round(OffsetX - propellerSize + yy);
                x2 = (int)Math.Round(OffsetX + propellerSize + yy);
                y1 = (int)Math.Round(OffsetY - propellerSize - xx);
                y2 = (int)Math.Round(OffsetY + propellerSize - xx);
                MyUtils.GDI.DrawXOREllipse(LayoutGraph, BirdsEyePen, x1, y1, x2, y2);
                MyUtils.GDI.DrawXORLine(LayoutGraph, BirdsEyePen, (int)OffsetX, (int)OffsetY,
                    (int)(OffsetX + (float)Math.Round(yy)), (int)(OffsetY - (float)Math.Round(xx)));
                DrawXORNum(LayoutGraph, 4, (int)(OffsetX + (float)Math.Round(yy)), (int)(OffsetY - (float)Math.Round(xx)));

                x1 = (int)Math.Round(OffsetX - propellerSize - xx);
                x2 = (int)Math.Round(OffsetX + propellerSize - xx);
                y1 = (int)Math.Round(OffsetY - propellerSize - yy);
                y2 = (int)Math.Round(OffsetY + propellerSize - yy);
                MyUtils.GDI.DrawXOREllipse(LayoutGraph, BirdsEyePen, x1, y1, x2, y2);
                MyUtils.GDI.DrawXORLine(LayoutGraph, BirdsEyePen, (int)OffsetX, (int)OffsetY,
                    (int)(OffsetX - (float)Math.Round(xx)), (int)(OffsetY - (float)Math.Round(yy)));
                DrawXORNum(LayoutGraph, 3, (int)(OffsetX - (float)Math.Round(xx)), (int)(OffsetY - (float)Math.Round(yy)));

                x1 = (int)Math.Round(OffsetX - propellerSize - yy);
                x2 = (int)Math.Round(OffsetX + propellerSize - yy);
                y1 = (int)Math.Round(OffsetY - propellerSize + xx);
                y2 = (int)Math.Round(OffsetY + propellerSize + xx);
                MyUtils.GDI.DrawXOREllipse(LayoutGraph, BirdsEyePen, x1, y1, x2, y2);
                MyUtils.GDI.DrawXORLine(LayoutGraph, BirdsEyePen, (int)OffsetX, (int)OffsetY,
                    (int)(OffsetX - (float)Math.Round(yy)), (int)(OffsetY + (float)Math.Round(xx)));
                DrawXORNum(LayoutGraph, 2, (int)(OffsetX - (float)Math.Round(yy)), (int)(OffsetY + (float)Math.Round(xx)));

                xx = ArmLen * (float)Math.Cos(AngleRads - 45 * MyUtils.D2R);
                yy = ArmLen * (float)Math.Sin(AngleRads - 45 * MyUtils.D2R);
                MyUtils.GDI.DrawXORLine(LayoutGraph, BirdsEyePen, (int)OffsetX, (int)OffsetY,
                    (int)(OffsetX + (float)Math.Round(xx)), (int)(OffsetY + (float)Math.Round(yy)));
            }
        }
        int Form1Paint = 0;
        bool EnablePntCnt = false;
        private void LBActCnt_Click(object sender, EventArgs e)
        {
            EnablePntCnt = !EnablePntCnt;
        }
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            if (EnablePntCnt) return;
            Form1Paint++;
            TBForm1PaintCnt.Text = Form1Paint.ToString();
        }
        int paintCnt2 = 0;
        bool InLocPaint = false;
        private void PBLocation_Paint(object sender, PaintEventArgs e)
        {
            if (InLocPaint) return;
            InLocPaint = true;

            DoLocationPaint = true;
            paintCnt2++;
            LBTrouble2.Text = "LocPaint" + paintCnt2.ToString();
            InLocPaint = false;
        }
        bool DoLocationPaint = false;
        int paintCnt = 0;
        bool InCopterPaint = false;
        private void PBCopters_Paint(object sender, PaintEventArgs e)
        {
            if (InCopterPaint) return;
            InCopterPaint = true;
            DoCopterPnt = true;
            LBTrShoot.Text = "CptrPaint" + paintCnt.ToString();
            InCopterPaint = false;
        }
        bool DoCopterPnt = false;
        int actCnt;
        private void Form1_Activated(object sender, EventArgs e)
        {
            actCnt++;
            LBActCnt.Text = actCnt.ToString();
//            PBCopters.Invalidate();
   //         PBLocation.Invalidate();
        }

        private void LBPathFile_Click(object sender, EventArgs e)
        {
        }
        DataGraph DatGraf = null;


        Browser MyBrowser = null;
        String URL = "";

        private void PBLocation_MouseUp(object sender, MouseEventArgs e)
        {
            if(InLoadFile) return;
            if (InLoadFileCnt < 20) return;
            double XLen = PBLocation.Size.Width - 6.0;
            double YLen = PBLocation.Size.Height;
            double XPerc = (double) e.X / XLen;
            double YPerc = 1.0 - ((double)e.Y / YLen);
            double Longitude = ((Eastest - Westest) * XPerc) + Westest;
            double Latitude = Northest - ((1/ScaleY) * (double) e.Y) ;
            double CenterLongitude = ((Eastest - Westest) * 0.5) + Westest;
            double CenterLatitude = ((Northest - Southest) * 0.5) + Southest;
            if (Math.Abs(CenterLatitude) < 0.01 && Math.Abs(CenterLongitude) < 0.01) return;
            DialogResult yn = MessageBox.Show("Map this point on Maps.Google?: Lon=" + Longitude.ToString() + "  Lat=" + Latitude.ToString(),"Maps.Google It?", MessageBoxButtons.YesNo);
            if (yn == DialogResult.Yes)
            {
                if (MyBrowser == null)
                {
                    MyBrowser = new Browser();
                    MyBrowser.Show();
                }
                else
                {
                    MyBrowser.Visible = true;
                    MyBrowser.BringToFront();
                }
//
                URL = "http://maps.google.com/maps?q=" + Latitude.ToString() + "," + Longitude.ToString() +
                    "&ll=" + CenterLatitude.ToString() + "," + CenterLongitude.ToString() +
                    "&spn=" + (Math.Abs(Northest - Southest).ToString()) + "," + (Math.Abs(Eastest - Westest).ToString()) +
                    "&t=h&v=0";

                MyBrowser.toolStripTextBox1.Text = URL;
                MyBrowser.Navigate(URL);
            }
        }

        private void BTAbout_Click(object sender, EventArgs e)
        {
            BigMessages bm = new BigMessages();
            bm.TBMessage.Text = @"
Hi all, This is ""APMLogVisualizer"" by Dan Gray
THIS PROGRAM IS BY NO MEANS FINISHED, but I already find it useful.
I hope you find it useful, but use at your own risk.

For a video on the features, check this out:
http://www.youtube.com/watch?v=bHKdHcs616o

Instructions:

This software is for LOG Files, not TLOG files.  TLOG files are created in the Mission 
Commander when you're connected by USB or Telemetry to the QuadCopter.  There is already 
a great built in viewer inside the mission planner for these files, but the only tool
for the ""LOG"" files is you can graph any particular item (or items).

But if you don't have telemetry, or if you want to log things that aren't logged in the 
TLOG files, it may be possible that the information is in the LOG files, that are saved 
inside the memory card on your APM2.

First, you should set up your APM2 to log the appropriate parts.
Using Mission Planner, you go to the TERMINAL button, wait until a bunch of text goes by, 
and the text says ""Ready To Fly"".....
then press enter 3 times.

It should end up saying ""Arducopter V2.5.5"" or your current version.

Now type:""LOGS<E>""
You should see a line that says:
logs enabled: ATTITUDE_MED GPS CTUN NTUN CMD CURRENT MOTORS

Your mileage may vary, depending on what you're logging.

APMLogVisualizer doesn't look at everything, but here's what it does ""look at""...

ATTITUDE, GPS, CMD, MODE, CURRENT, MOTORS, NTUN and CTUN

At this point, only the PM is not graphed or displayed.

If you don't have ATTITUDE, GPS, CMD, CURRENT, MOTORS, CTUN, and NTUN enabled, then enable 
them one by one.  The only thing to watch out for is to enable ""CURRENT"" you have to type 
""ENABLE CUR<e>"" instead of ""ENABLE CURRENT<E>"".  

Now, I'm assuming you know how to save the log files using the mission commander 
""Terminal/LogDownload"".  If not, go here:
http://code.google.com/p/arducopter/wiki/AC2_Logs

Next you need to open a log file.
You can set up your ""MyComputer"" to automatically run this program by right clicking 
on a log file then selecting ""Open With"", and browse to APMLogVisualizer.exe.  Make 
sure the checkbox that says something about ""Always open with"" is checked.

You can run APMLogVisualizer.exe directly, too, then click on ""Load APM2 Log File"" , 
browse to your file, and open it.

Once a file is open, in the large area on the left, you'll see the GPS path that the Copter 
took during this log.  I call this the ""Path Area"". At the bottom is an arrow with an 
indicator of how many meters in Longitude the copter went.  On the right of this area
is a brown bar graph of GPS altitude, and at the top right the highest altitude that 
the copter went is diplayed after the text: ""Verticle Height"".  

The path that the copter took is colored, Red for ""Stabilize"" mode, Magenta for ""Loiter
Mode"", and Green for ""Auto Mode"".  Also, if there are any waypoints, they're displayed 
in this area of the screen, as a thick black circle.

You can click anywhere on the map, and a browser will open and if you've an I-Net connection, 
Maps.Google will display the aerial view of the center of motion for your copter. It will 
put a mark on the map where you clicked in the Path area.

In the text box area at the top right is all the data that's displayed from the log.
This includes GPS data (including Universal and local time), 
then all of the Attitidue data including heading, pitch, roll, yaw, 
the motor signals, the volts and amps (You have to have a voltage and amperage sensor),
then All of the CTUN and NTUN parameters.

The current MODE that the copter is in (Stabilize, RTL, Loiter, etc), 
and the latest command if in the Auto mode, along with the command parameters.

If the Text is GREEN, then you can click on it, and an Engineering Graph will appear.
You can click on up to 8 points, and they will all be displayed.
Once you've clicked on a point, the color turns to red, indicating that it's on the graph.
To clear the graph, click on the ""Clear Graph"" button.
To delete a point that's already on the graph, click on the Red text again, or 
right click on the point name that you want to delete, in the engineering graph.

A REALLY Cool feature starting with version 1.13 is the main window display is updated
with the location that the slider in the graph is on!  Wow, all the digital readouts
in the main window are updated where you have the slider in a graph!  Now that is
COOL!

When a graph is up, click on the graph title at the top, for a graph help window.

In the bottom right portion of the screen is a graphic representation of a Copter, indicating 
the current Roll, Pitch, and Heading of the machine.

You can grab the slider at the bottom of the screen (I call this the ""Log Pointer"" slider), 
and drag it anywhere in the file.  To the very right is the end of the file, the very left 
is the beginning of the file.  You can watch the little X work around the path as you move 
this slider, also, all of the numbers change to the current value for that portion of the log.

If you have a graph open, there will be a bar, indicating where the current ""LogLines Pointer""
is.

You can ""play"" the log file by clicking on ""PlayLogRev"" or ""PlayLogFwd"". 
You'll see the numbers change, and the ""little guy"" will run around the path the copter took.

You can change the playback speed with the smaller slider on top of the Log Pointer slider.

If you want to improve this program, please ask me for the project source, as long as you're 
willing to share the source and exe with the community, and I decide you're worthy, I'll let 
you use it.

Dan Gray
grayarea1@tms-usa.com

";
                bm.Text = "APMLogVisualizer version " + MyVersion + "  by Dan Gray";
                bm.ShowDialog();
        }

        private void ClearGraph()
        {
            DatGraf.ClearGraph();
        }
        private void BTClearGraph_Click(object sender, EventArgs e)
        {
            ClearGraph();
        }

        bool AddDataPoint(String labelx, String Desc, float[] fa, float zero, float span, int dp)
        {
            if (DatGraf != null)
            {
                DatGraf.Visible = true;
                DatGraf.BringToFront();
                return DatGraf.AddLine2Graph(labelx, Desc, fa, NoOfLogEntries, zero, span, dp);
            }
            return false;
        }
        void DoLabelColors()
        {
            if (DatGraf == null) return;
            DatGraf.IsLabelOnGraph(LBAmpsTotal, "AmpsTotal");
            DatGraf.IsLabelOnGraph(LBAmps, "Amps");
            DatGraf.IsLabelOnGraph(LBVolts, "Volts");
            DatGraf.IsLabelOnGraph(LBRoll, "Roll");
            DatGraf.IsLabelOnGraph(LBPitch, "Pitch");
            DatGraf.IsLabelOnGraph(LBYaw, "Yaw");
            DatGraf.IsLabelOnGraph(LBMot1, "Motor 1");
            DatGraf.IsLabelOnGraph(LBMot2, "Motor 2");
            DatGraf.IsLabelOnGraph(LBMot3, "Motor 3");
            DatGraf.IsLabelOnGraph(LBMot4, "Motor 4");
            DatGraf.IsLabelOnGraph(LBMagHead, "Magnetic Heading");
            DatGraf.IsLabelOnGraph(LBGPSSPeed, "Speed");
            DatGraf.IsLabelOnGraph(LBLat, "Latitude");
            DatGraf.IsLabelOnGraph(LBLon, "Longitude");
            DatGraf.IsLabelOnGraph(LBGPSAlt, "GPSAltitude");
            DatGraf.IsLabelOnGraph(LBThrot, "Throttle");
            DatGraf.IsLabelOnGraph(LBCurMode, "Mode");
            DatGraf.IsLabelOnGraph(LBNTunWPDist, "WPDist");
            DatGraf.IsLabelOnGraph(LBNTTargetBearing, "NTTargBear");
            DatGraf.IsLabelOnGraph(LBNTLonErr, "LongErr");
            DatGraf.IsLabelOnGraph(LBNTLatErr, "LatErr");
            DatGraf.IsLabelOnGraph(LBNTNavLon, "NavLon");
            DatGraf.IsLabelOnGraph(LBNTNavLat, "NavLat");
            DatGraf.IsLabelOnGraph(LBNTYSpeed, "YSpeed");
            DatGraf.IsLabelOnGraph(LBNTXSpeed, "XSpeed");
            DatGraf.IsLabelOnGraph(LBNTNavLonI, "NavLonI");
            DatGraf.IsLabelOnGraph(LBNTNavLatI, "NavLatI");
            DatGraf.IsLabelOnGraph(LBCTThrotIn, "ThrottleIn");
            DatGraf.IsLabelOnGraph(LBCTSonarAlt, "Sonar_Alt");
            DatGraf.IsLabelOnGraph(LBGPSLT, "GPS_LT");
            DatGraf.IsLabelOnGraph(LBRelAlt, "MixAlt");
            DatGraf.IsLabelOnGraph(LBCTThrotI, "ThrotInt");
            DatGraf.IsLabelOnGraph(LBCTAltHoldI, "AltHoldInt");
            DatGraf.IsLabelOnGraph(LBCTRC3Out, "RC3ServoOut");
            DatGraf.IsLabelOnGraph(LBCTClimbRate, "CLimbRate");
            DatGraf.IsLabelOnGraph(LBCTunManBoost, "ManBoost");
            DatGraf.IsLabelOnGraph(LBCTAngBoost, "AngleBoost");
            DatGraf.IsLabelOnGraph(LBCTNavThrot, "NavThrottle");
            DatGraf.IsLabelOnGraph(LBCTWPAlt, "WP_Alt");
            DatGraf.IsLabelOnGraph(LBCTBaroAlt, "Baro_Alt");
        }

        private void LBAmpsTotal_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CurrCurrentTotal;
            AddDataPoint("AmpsTotal", "RunningTotal of Amps...", fa, 0, 0, 1);
        }

        private void LBAmps_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CurrCurrent;
            AddDataPoint("Amps", "Amperage of this log...", fa, 0, 0, 1);
        }

        private void LBVolts_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CurrVoltage;
            AddDataPoint("Volts", "Voltage of this log...", fa, 6, 18, 1);
        }

        private void LBRoll_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].Roll;
            AddDataPoint("Roll", "", fa, -45, 45, 1);
        }

        private void LBPitch_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].Pitch;
            AddDataPoint("Pitch", "", fa, -45, 45, 1);
        }

        private void LBYaw_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].Yaw;
            AddDataPoint("Yaw", "", fa, 0, 360, 1);
        }

        private void LBMot1_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].Mot1;
            AddDataPoint("Motor 1", "", fa, 1000, 2000, 0);
        }

        private void LBMot2_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].Mot2;
            AddDataPoint("Motor 2", "", fa, 1000, 2000, 0);
        }

        private void LBMot3_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].Mot3;
            AddDataPoint("Motor 3", "", fa, 1000, 2000, 0);
        }

        private void LBMot4_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].Mot4;
            AddDataPoint("Motor 4", "", fa, 1000, 2000, 0);
        }

        private void LBMagHead_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].MagHeading;
            AddDataPoint("Magnetic Heading", "", fa, 0, 360, 1);

        }

        private void LBGPSSPeed_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].GRSpeed;
            AddDataPoint("Speed", "", fa, 0, 0, 1);
        }

        private void LBLat_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].Lat;
            AddDataPoint("Latitude", "", fa, 0, 0, 6);
        }

        private void LBLon_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].Lon;
            AddDataPoint("Longitude", "", fa, 0, 0, 6);
        }

        private void LBGPSAlt_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].GPSAlt;
            AddDataPoint("GPSAltitude", "GPSAltitude", fa, 0, 0, 1);
        }
        private void LBThrot_Click(object sender, EventArgs e)
        {
                float[] fa = new float[NoOfLogEntries];
                for (int i = 0; i < NoOfLogEntries; i++)  fa[i]  = (float)lpi[i].CurrThrottleIn;
                AddDataPoint("Throttle", "Throttle Value", fa, 0, 1000, 2);
        }
        private void LBCurMode_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].Mode;
            AddDataPoint("Mode", "Copter Mode", fa, 0, 10, 0);
        }

// NTun, Navigation Tuning Stuff here
        private void LBNTunWPDist_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].NTunWPDist;
            AddDataPoint("WPDist", "Nav Tune Waypoint Distance", fa, 0, 0, 1);
        }

        private void LBNTTargetBearing_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].NTunTargetBearing;
            AddDataPoint("NTTargBear", "Nav Tune Target Bearing", fa, 0, 360, 1);
        }

        private void LBNTLonErr_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].NTunLonErr;
            AddDataPoint("LongErr", "Nav Tune Longitude Error", fa, -5000, 5000, 0);
        }
        private void LBNTLatErr_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].NTunLatErr;
            AddDataPoint("LatErr", "Nav Tune Latitude Error", fa, -5000, 5000, 0);
        }

        private void LBNTNavLon_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].NTunNavLon;
            AddDataPoint("NavLon", "Nav Tune Navigation Longitude", fa, -5000, 5000, 0);
        }

        private void LBNTNavLat_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].NTunNavLat;
            AddDataPoint("NavLat", "Nav Tune Navigation Latitude", fa, -5000, 5000, 0);
        }

        private void LBNTXSpeed_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].NTunXSpeed;
            AddDataPoint("XSpeed", "Nav Tune X Speed", fa, -2000, 2000, 0);
        }

        private void LBNTYSpeed_Click(object sender, EventArgs e)
        {

            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].NTunYSpeed;
            AddDataPoint("YSpeed", "Nav Tune Y Speed", fa, -2000, 2000, 0);
        }

        private void LBNTNavLonI_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].NTunNavLonI;
            AddDataPoint("NavLonI", "Nav Tune Navigation Longitude Integral", fa, 0, 0, 0);
        }

        private void LBNTNavLatI_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].NTunNavLatI;
            AddDataPoint("NavLatI", "Nav Tune Navigation Latitude Integral", fa, 0, 0, 0);
        }
        //Now we are doing the CTUN stuff
        private void LBCTThrotIn_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunThrotIn;
            AddDataPoint("ThrottleIn", "", fa, 0, 1000, 0);
        }

        private void LBCTSonarAlt_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunSonarAlt;
            AddDataPoint("Sonar_Alt", "", fa, 0, 1000, 0);
        }

        private void LBCTBaroAlt_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunBaroAlt;
            AddDataPoint("Baro_Alt", "", fa, 0, 0, 0);
        }

        private void LBCTWPAlt_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunWPAlt;
            AddDataPoint("WP_Alt", "", fa, 0, 0, 0);
        }

        private void LBCTNavThrot_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunNavThrottle;
            AddDataPoint("NavThrottle", "", fa, -100, 100, 0);
        }
        private void LBCTAngBoost_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunAngleBoost;
            AddDataPoint("AngleBoost", "", fa, 0, 100, 0);
        }

        private void LBCTunManBoost_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunManualBoost;
            AddDataPoint("ManBoost", "", fa, 0, 100, 0);
        }

        private void LBCTClimbRate_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunClimbRate;
            AddDataPoint("CLimbRate", "", fa, -1000, 1000, 0);
        }

        private void LBCTRC3Out_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunRC3ServoOut;
            AddDataPoint("RC3ServoOut", "", fa, 0, 1000, 0);
        }

        private void LBCTAltHoldI_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunAltHoldInt;
            AddDataPoint("AltHoldInt", "", fa, 0, 0, 0);
        }

        private void LBCTThrotI_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].CTunThrottleInt;
            AddDataPoint("ThrotInt", "", fa, 0, 0, 0);
        }

        private void LBRelAlt_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].MixAlt;
            AddDataPoint("MixAlt", "Mix Altitude", fa, 0, 0, 1);
        }

        private void LBGPSLT_Click(object sender, EventArgs e)
        {
            float[] fa = new float[NoOfLogEntries];
            for (int i = 0; i < NoOfLogEntries; i++) fa[i] = (float)lpi[i].mSecs;
            AddDataPoint("GPS_LT", "GPS Time In Seconds", fa, 0, 0, 1);
        }
        bool MouDownInTrackBar = false;
        private void TrBCurStep_MouseDown(object sender, MouseEventArgs e)
        {
            MouDownInTrackBar = true;

        }
        private void TrBCurStep_MouseUp(object sender, MouseEventArgs e)
        {
            MouDownInTrackBar = false;
        }

    }
//https://maps.google.com/maps?q=45.5662210,-122.7020750&hl=en&ll=45.566306,-122.701683&spn=0.001322,0.002061&sll=37.0625,-95.677068&sspn=67.67529,135.087891&t=h&z=20
    internal class LogPointInfo
    {
        //gps stuff
        internal int mSecs;
        internal int Sats;
        internal double Lat;
        internal double Lon;
        internal double GPSAlt;
        internal double MixAlt;
        internal double GRSpeed;
        internal double CRS;

        //gyro, compass stuff
        internal double RollIN;
        internal double Roll;
        internal double PitchIN;
        internal double Pitch;
        internal double YawIN;
        internal double Yaw;
        internal double MagHeading;
        //motor stuff
        internal double Mot1;
        internal double Mot2;
        internal double Mot3;
        internal double Mot4;
//5 is CMDTotal, 1 is CMDCurrentNum, 16 is CMDID, 1 is CMDOptions, 10 is CMDP1, 3500 is CMDALT, 455667456 is CMDLat, -1227033216 is CMDLon
//CMD, 5, 1, 16, 1, 10, 3500, 455667456, -1227033216
//CMD, 5, 2, 16, 1, 10, 3500, 455665504, -1227036416
//CMD, 5, 3, 16, 1, 10, 3500, 455663616, -1227028352
//CMD, 5, 4, 20, 1, 0, 0, 0, 0

        //command stuff
        internal int Mode = 0;
        internal int CMDTotal;
        internal int CMDCurrentNum;
        internal int CMDID;
        internal int CMDOptions;
        internal int CMDP1;
        internal double CMDAlt;
        internal double CMDLat;
        internal double CMDLon;

//NTUN, 346, 344, -84, 300, -90, 240, 32, -48, -5, 33
        //NTUN Stuff (Navigational tuning)
        internal double NTunWPDist;
        internal double NTunTargetBearing;
        internal double NTunLonErr;
        internal double NTunLatErr;
        internal double NTunNavLon;
        internal double NTunNavLat;
        internal double NTunXSpeed;
        internal double NTunYSpeed;
        internal double NTunNavLonI;
        internal double NTunNavLatI;

//CTUN, 460, 383, 59, 650, -5, 0, 0, 96, 416, 1, 1
        //CTUN STuff (Control Axis tuning)
        internal double CTunThrotIn;
        internal double CTunSonarAlt;
        internal double CTunBaroAlt;
        internal double CTunWPAlt;
        internal double CTunNavThrottle;
        internal double CTunAngleBoost;
        internal double CTunManualBoost;
        internal double CTunClimbRate;
        internal double CTunRC3ServoOut;
        internal double CTunAltHoldInt;
        internal double CTunThrottleInt;

        //PM STuff (IMU Performance)
        internal double GyroSaturation;
        internal double ADCConstraints;
        internal double DCMRenorms;
        internal double DCMBlowUps;
        internal double GPSFixCount;

        //CURRENT Stuff
        internal double CurrThrottleIn;
        internal double CurrThrottleTotal;
        internal double CurrVoltage;
        internal double CurrCurrent;
        internal double CurrCurrentTotal;

    }
}
